﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;

namespace FlaUIGameTools
{
    public static class Hwnd
    {

        public const uint BM_CLICK = 0xF5; //鼠标点击的消息，对于各种消息的数值，大家还是得去API手册
        public const uint WM_SETTEXT = 0x000C;

        public const uint WM_COPY = 0x0301;

        public const int WM_LBUTTONDOWN = 0x201;
        public const int WM_LBUTTONUP = 0x202;
        public const int WM_RBUTTONDOWN = 0x204;
        public const int WM_RBUTTONUP = 0x205;



        public const int WM_GETTEXT = 0x000D;
        public const int WM_GETTEXTLENGTH = 0x000E;
        public const int BM_GETSTATE = 0x00F2;
        public const int BM_GETCHECK = 0x00F0;


        //按下一个键
        public static uint WM_KEYDOWN = 0x0100;
        //释放一个键
        public static uint WM_KEYUP = 0x0101;

        //按下一个系统键
        public static uint WM_SYSKEYDOWN = 0x0104;
        //释放一个系统键
        public static uint WM_SYSKEYUP = 0x0105;

        public const int WM_CHAR = 0x0102;

        //结构体布局 本机位置
        [StructLayout(LayoutKind.Sequential)]
        public struct NativeRECT
        {
            public int left;
            public int top;
            public int right;
            public int bottom;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct WINDOWPLACEMENT
        {
            int length;
            int flags;
            int showCmd;
            Point ptMinPosition;
            Point ptMaxPosition;
            NativeRECT rcNormalPosition;
        }

        //将枚举作为位域处理
        [Flags]
        enum MouseEventFlag : uint //设置鼠标动作的键值
        {
            Move = 0x0001,               //发生移动
            LeftDown = 0x0002,           //鼠标按下左键
            LeftUp = 0x0004,             //鼠标松开左键
            RightDown = 0x0008,          //鼠标按下右键
            RightUp = 0x0010,            //鼠标松开右键
            MiddleDown = 0x0020,         //鼠标按下中键
            MiddleUp = 0x0040,           //鼠标松开中键
            XDown = 0x0080,
            XUp = 0x0100,
            Wheel = 0x0800,              //鼠标轮被移动
            VirtualDesk = 0x4000,        //虚拟桌面
            Absolute = 0x8000
        }
        public enum ShowStatus : int
        {
            SW_HIDE = 0,
            SW_SHOW = 5
        }

        public const int SW_HIDE = 0;

        [DllImport("user32.dll", EntryPoint = "ShowWindow")]
        public static extern bool ShowWindow(IntPtr hwnd, ShowStatus nCmdShow);

        [DllImport("user32.dll")]
        public static extern bool EnableWindow(IntPtr hWnd, bool bEnable);//设置Enable属性
        //设置鼠标位置
        [DllImport("user32.dll")]
        static extern bool SetCursorPos(int X, int Y);

        //判断句柄是否存在
        [DllImport("user32.dll")]
        public static extern bool IsWindow(IntPtr hwnd);

        //判断句柄是否显示
        [DllImport("user32.dll")]
        public static extern bool IsWindowVisible(IntPtr hwnd);

        //判断句柄是否繁忙
        [DllImport("user32.dll")]
        public static extern bool IsHungAppWindow(IntPtr hwnd);

        [DllImport("user32.dll")]
        public static extern IntPtr SetFocus(IntPtr hWnd);

        [DllImport("user32.dll")]
        public static extern int GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT wp);

        //设置鼠标按键和动作
        [DllImport("user32.dll")]
        static extern void mouse_event(MouseEventFlag flags, int dx, int dy, uint data, IntPtr extraInfo); //UIntPtr指针多句柄类型

        [DllImport("user32.dll")]
        public static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);

        [DllImport("user32.dll")]
        public static extern bool GetWindowRect(IntPtr hwnd, out NativeRECT rect);

        [DllImport("user32.dll")]
        static extern IntPtr FindWindow(string strClass, string strWindow);

        //该函数获取一个窗口句柄,该窗口雷鸣和窗口名与给定字符串匹配 hwnParent=Null从桌面窗口查找
        [DllImport("user32.dll")]
        public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string strClass, string strWindow);

        //根据坐标获取窗口句柄
        [DllImport("user32")]
        public static extern IntPtr WindowFromPoint(Point Point);

        [DllImport("user32")]
        public static extern IntPtr ChildWindowFromPoint(IntPtr hWndParent, Point p);

        /// <summary>
        /// 按在坐标寻找子窗口
        /// </summary>
        /// <param name="hWndParent">父窗口句柄</param>
        /// <param name="p">坐标</param>
        /// <param name="f">寻找参数 0-任何窗口  1-查找显示的子窗口 2-查找隐藏的子窗口 3-查找透明窗口</param>
        /// <returns></returns>
        [DllImport("user32")]
        public static extern IntPtr ChildWindowFromPointEx(IntPtr hWndParent, Point p, uint f);

        [DllImport("user32.dll")]
        static extern bool SetActiveWindow(IntPtr hwnd);

        [DllImport("user32.dll")]
        public static extern bool SetWindowText(IntPtr hwnd, string lpString);

        [DllImport("user32.dll")]
        public static extern bool FlashWindow(IntPtr hWnd, bool bInvert);

        [DllImport("user32.dll")]
        static extern bool GetClientRect(IntPtr hwnd, out NativeRECT rect);

        [DllImport("user32.dll", EntryPoint = "FindWindowEx", SetLastError = true)]
        public static extern IntPtr FindWindowEx(IntPtr hwndParent, uint hwndChildAfter, string lpszClass, string lpszWindow);

        [DllImport("user32.dll", EntryPoint = "SendMessage", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern int SendMessage(IntPtr hwnd, uint wMsg, int wParam, int lParam);

        [DllImport("User32.DLL")]
        public static extern int PostMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);


        [DllImport("User32.DLL")]
        public static extern int SendMessage(IntPtr hWnd, uint Msg, int wParam, string lParam);

        [DllImport("user32.dll", EntryPoint = "SendMessageA")]
        public static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, byte[] lParam);


        [DllImport("user32.dll", EntryPoint = "SetForegroundWindow", SetLastError = true)]
        public static extern void SetForegroundWindow(IntPtr hwnd);

        /// <summary>
        /// 用于枚举子窗体是的委托
        /// </summary>
        /// <param name="WindowHandle">窗体句柄</param>
        /// <param name="num">自定义</param>
        /// <returns></returns>
        public delegate bool EnumChildWindow(IntPtr WindowHandle, string num);
        /// <summary>
        /// 获取指定窗体的所有子窗体
        /// </summary>
        /// <param name="WinHandle">窗体句柄</param>
        /// <param name="ec">回调委托</param>
        /// <param name="name">自定义</param>
        /// <returns></returns>
        [DllImport("User32.dll")]
        public static extern int EnumChildWindows(IntPtr WinHandle, EnumChildWindow ecw, string name);
        /// <summary>
        /// 获取指定窗体的标题
        /// </summary>
        /// <param name="WinHandle">窗体句柄</param>
        /// <param name="Title">缓冲区取用于存储标题</param>
        /// <param name="size">缓冲区大小</param>
        /// <returns></returns>
        [DllImport("User32.dll")]
        public static extern int GetWindowText(IntPtr WinHandle, StringBuilder Title, int size);

        /// <summary>
        /// 获取窗体类型
        /// </summary>
        /// <param name="WinHandle">窗体句柄</param>
        /// <param name="Type">类型</param>
        /// <param name="size">缓冲区大小</param>
        /// <returns></returns>
        [DllImport("user32.dll")]
        public static extern int GetClassName(IntPtr WinHandle, StringBuilder Type, int size);

        /// <summary>
        /// 根据句柄获得进程id值
        /// </summary>
        /// <param name="handle">句柄</param>
        /// <param name="pid"></param>
        /// <returns></returns>
        [DllImport("user32")]
        private static extern int GetWindowThreadProcessId(IntPtr handle, out int pid);

        [DllImport("user32.dll ", EntryPoint = "GetDlgItem")]
        public static extern IntPtr GetDlgItem(IntPtr hParent, int nIDParentItem);

        /// <summary>
        /// 根据CLASSNAME和坐标查找句柄
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="classname"></param>
        /// <param name="left"></param>
        /// <param name="top"></param>
        /// <returns></returns>
        public static IntPtr FindHndByClassAndXY(IntPtr ip, string classname, int left, int top, IntPtr RootHnw)
        {
            NativeRECT faRect;
            if (RootHnw != IntPtr.Zero)
            {
                GetWindowRect(RootHnw, out faRect);
            }
            else
            {
                GetWindowRect(ip, out faRect);
            }
            IntPtr tip = IntPtr.Zero;
            NativeRECT chRect;
            while (true)
            {
                tip = FindWindowEx(ip, tip, classname, null);
                if (tip != IntPtr.Zero)
                {
                    GetWindowRect(tip, out chRect);
                    if (chRect.top - faRect.top == top && chRect.left - faRect.left == left)
                    {
                        if (IsWindowVisible(tip))
                        {
                            return tip;
                        }
                    }
                }
            }
        }
        /// <summary>
        /// 根据CLASSNAME和绝对高度查找句柄
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="classname"></param>
        /// <param name="left"></param>
        /// <param name="top"></param>
        /// <returns></returns>
        public static IntPtr FindHndByClassAndY(IntPtr ip, string classname, int top)
        {

            IntPtr tip = IntPtr.Zero;
            NativeRECT chRect;
            while (true)
            {
                tip = FindWindowEx(ip, tip, classname, null);
                if (tip != IntPtr.Zero)
                {
                    GetWindowRect(tip, out chRect);
                    if (chRect.top == top)
                    {
                        if (IsWindowVisible(tip))
                        {
                            return tip;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 根据CLASSNAME和大小查找句柄
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="classname"></param>
        /// <param name="left"></param>
        /// <param name="top"></param>
        /// <returns></returns>
        public static IntPtr FindHndByClassAndSize(IntPtr ip, string classname, int width, int height)
        {
            IntPtr tip = IntPtr.Zero;
            NativeRECT chRect;
            while (true)
            {
                tip = FindWindowEx(ip, tip, classname, null);
                if (tip != IntPtr.Zero)
                {
                    GetClientRect(tip, out chRect);
                    if (chRect.right == width && chRect.bottom == height)
                    {
                        if (IsWindowVisible(tip))
                        {
                            return tip;
                        }
                    }
                }
            }
        }


        /// <summary>
        /// 传入窗口名称和进程ID查找到窗口 若查询不到可持续查找等待窗口出现
        /// </summary>
        /// <param name="name"></param>
        /// <param name="pid"></param>
        /// <returns></returns>
        public static IntPtr FindTopHndByName(string name, int pid)
        {
            IntPtr ip = IntPtr.Zero;
            while (true)
            {
                ip = FindWindowEx(IntPtr.Zero, ip, null, name);
                if (ip != IntPtr.Zero)
                {
                    int tpid = 0;
                    GetWindowThreadProcessId(ip, out tpid);
                    if (tpid == pid)
                    {
                        return ip;
                    }
                }
            }
        }

        /// <summary>
        /// 传入窗口名称和进程ID查找到窗口 若查询不到可持续查找等待窗口出现,仅执行一圈
        /// </summary>
        /// <param name="name"></param>
        /// <param name="pid"></param>
        /// <returns></returns>
        public static IntPtr FindTopHndByName_ONCE(string name, int pid)
        {
            IntPtr startHwnd = IntPtr.Zero;
            IntPtr ip = IntPtr.Zero;
            while (true)
            {
                ip = FindWindowEx(IntPtr.Zero, ip, null, name);
                if (ip != IntPtr.Zero)
                {
                    if (startHwnd == ip)
                    {
                        return IntPtr.Zero;
                    }
                    int tpid = 0;
                    GetWindowThreadProcessId(ip, out tpid);
                    if (tpid == pid)
                    {
                        return ip;
                    }
                    if (startHwnd == IntPtr.Zero)
                    {
                        startHwnd = ip;
                    }
                }
                else
                {
                    return IntPtr.Zero;
                }
            }
        }

        /// <summary>
        /// 传入窗口类名、进程ID、子级句柄名定位窗口
        /// </summary>
        /// <param name="classname"></param>
        /// <param name="pid"></param>
        /// <param name="childname"></param>
        /// <returns></returns>
        public static IntPtr FindHndByClass(string classname, int pid, string childname)
        {
            IntPtr ip = IntPtr.Zero;
            while (true)
            {
                ip = FindWindowEx(IntPtr.Zero, ip, classname, null);
                if (ip != IntPtr.Zero)
                {
                    int tpid = 0;
                    GetWindowThreadProcessId(ip, out tpid);
                    if (tpid == pid)
                    {
                        IntPtr ip2 = FindWindowEx(ip, 0, null, childname);
                        if (ip2 != IntPtr.Zero)
                        {
                            return ip;
                        }
                    }
                }
            }
        }

        public static IntPtr FindHndByClassAnPid(int pid,string classname)
        {
            IntPtr ip = IntPtr.Zero;
            while (true)
            {
                ip = FindWindowEx(IntPtr.Zero, ip, classname, null);
                if (ip != IntPtr.Zero)
                {
                    int tpid = 0;
                    GetWindowThreadProcessId(ip, out tpid);
                    if (tpid == pid)
                    {
                        return ip;
                    }
                }
            }
        }

        /// <summary>
        /// 按名称查找某个窗口下的句柄
        /// </summary>
        /// <param name="name"></param>
        /// <param name="wh"></param>
        /// <returns></returns>
        public static IntPtr FindWH_Name_While(string name, IntPtr wh)
        {
            IntPtr ip;
            while (true)
            {
                ip = FindWindowEx(wh, 0, null, name);
                if (ip == IntPtr.Zero)
                {
                    Thread.Sleep(100);
                }
                else
                {
                    return ip;
                }
            }
        }

        /// <summary>
        /// 按名称-递归-查找某个窗口下的句柄
        /// </summary>
        /// <param name="name"></param>
        /// <param name="wh"></param>
        /// <returns></returns>
        public static IntPtr FindWH_Class_Table(string table, IntPtr father, bool isShow)
        {
            string[] classs = table.Split('>');
            for (int i = 0; i < classs.Length; i++)
            {
                IntPtr ip = IntPtr.Zero;
                while (true)
                {
                    ip = FindWindowEx(father, ip, classs[i], null);
                    if (IsWindowVisible(ip) == isShow)
                    {
                        father = ip;
                        break;
                    }
                }
            }
            return father;
        }


        /// <summary>
        /// 按类名查找某个窗口下的句柄
        /// </summary>
        /// <param name="classn"></param>
        /// <param name="wh"></param>
        /// <returns></returns>
        public static IntPtr FindWH_Class_While(string classn, IntPtr wh)
        {
            IntPtr ip;
            while (true)
            {
                ip = FindWindowEx(wh, 0, classn, null);
                if (ip == IntPtr.Zero)
                {
                    Thread.Sleep(100);
                }
                else
                {
                    return ip;
                }
            }
        }


        public static void InputStr(IntPtr hwd, string str)
        {
            Hwnd.SendMessage(hwd, Hwnd.WM_SETTEXT, 0, str);
            Hwnd.SetWindowText(hwd, str);
        }

        /// <summary>
        /// 以sendmessage形式获取文本框中输入的内容
        /// </summary>
        /// <param name="ip">对象句柄</param>
        /// <returns>获取的文本 获取不到返回null或者空</returns>
        public static string GetHndText(IntPtr ip)
        {
            if (ip != IntPtr.Zero)
            {
                int TextLen;
                TextLen = Hwnd.SendMessage(ip, Hwnd.WM_GETTEXTLENGTH, 0, 0);
                byte[] byt = new byte[TextLen];
                Hwnd.SendMessage(ip, Hwnd.WM_GETTEXT, TextLen + 1, byt);
                string str = Encoding.Default.GetString(byt);
                return str;
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// 模拟按键输入字符串-只能输入A-Z a-z 0-9
        /// </summary>
        /// <param name="dtpHwnd">需要输入的句柄</param>
        /// <param name="str">字符串</param>
        public static void InputStr_KEY(IntPtr Hwnd, string str)
        {
            for (int i = 0; i < str.Length; i++)
            {
                PostMessage(Hwnd, WM_CHAR, str[i], 0);
                Thread.Sleep(10);
            }
            return;
        }


    }
}
